/**
	Pulsar engine. Additional include file.
	Windows template dialog boxes

	Copyright (C) 2013-2014 Dmitry Dolgov

	This program is free software; you can redistribute it and/or modify it under the terms of the
	GNU General Public License as published by the Free Software Foundation; either version 2 of
	the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
	without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
	See the GNU General Public License for more details.
*/

#include <pulsar/pulsar.h>

namespace pl
{

const size_t _MEM_BLOCK_SIZE = 4096;

/**
	\param windowStyle WS_* styles
	\param title window title
	\param rect size of window
	\param windowExStyle WS_EX_* styles
	DlgTemplate ctor
*/
DlgTemplate::DlgTemplate(DWORD windowStyle, const pl_char* title, const RECT& rect, DWORD windowExStyle /*= 0*/) :
_pMemory((pl_uint8*)LocalAlloc(LPTR, _MEM_BLOCK_SIZE)),
_curSize(0),
_memSize(_MEM_BLOCK_SIZE),
_pNControls(NULL),
_hglb(NULL)
{
	WORD zeroWord = 0;

	_add(&windowStyle, sizeof(DWORD));
	_add(&windowExStyle, sizeof(DWORD));

	_pNControls = (pl_uint16*)(_pMemory + _curSize);
	_add(&zeroWord, sizeof(WORD)); // N controls
	_add(&rect.left, sizeof(WORD));
	_add(&rect.top, sizeof(WORD));
	_add(&rect.right, sizeof(WORD));
	_add(&rect.bottom, sizeof(WORD));
	_add(&zeroWord, sizeof(WORD)); // No menu
	_add(&zeroWord, sizeof(WORD)); // Use standard dialog class
	_add(title ? title : PL_T(""));

	if (windowStyle & DS_SETFONT)
	{
		// Standard font
		WORD fontSize = 8;
		_add(&fontSize, sizeof(WORD));
		_add(PL_T("MS Sans Serif"));
		_align(sizeof(DWORD));
	}
	return;
}

/**
	DlgTemplate dtor
*/
DlgTemplate::~DlgTemplate()
{
	if (_pMemory != NULL)
	{
		LocalFree(_pMemory);
	}
	if (_hglb != NULL)
	{
		GlobalFree(_hglb);
	}
	return;
}

/**
	\param style WS_* control styles
	\param exStyle WS_EX_* extended control styles
	\param rect size of control
	\param id control identifier
	\param wndClass class name (either standard or own)
	\param title control title
	Addnew control to dialog template
*/
void DlgTemplate::addControl(DWORD style, DWORD exStyle, const RECT& rect, int id, const pl_char* wndClass, const pl_char* title)
{
	_align(sizeof(DWORD));

	style |= WS_CHILD;
	_add(&style, sizeof(DWORD)); 
	_add(&exStyle, sizeof(DWORD));
	_add(&rect.left, sizeof(WORD));
	_add(&rect.top, sizeof(WORD));
	_add(&rect.right, sizeof(WORD));
	_add(&rect.bottom, sizeof(WORD));
	_add(&id, sizeof(WORD));
	_add(wndClass);

	_add(title);

	WORD zeroByte = 0;
	_add(&zeroByte, sizeof(WORD));

	(*_pNControls)++;
	return;
}

/**
	get pointer to pass to DialogBoxIndirect()
*/
LPCDLGTEMPLATE DlgTemplate::getGlobalMem()
{
	if (_hglb != NULL)
	{
		return (LPCDLGTEMPLATE)_hglb;
	}
	if (_pMemory == NULL)
	{
		return NULL;
	}
	_hglb = GlobalAlloc(GMEM_ZEROINIT, _curSize);
	if (_hglb == NULL)
	{
		return NULL;
	}
	LPVOID p = GlobalLock(_hglb);
	if (p == NULL)
	{
		GlobalFree(_hglb);
		_hglb = NULL;
		return NULL;
	}
	memcpy(p, _pMemory, _curSize);
	GlobalUnlock(_hglb);
	return (LPCDLGTEMPLATE)_hglb;
}

/**
	Add new data into template
*/
void DlgTemplate::_add(const void* p, size_t size)
{
	_expand(size);
	memcpy(_pMemory + _curSize, p, size);
	_curSize += size;
	return;
}

/**
	Add new data into template (string)
*/
void DlgTemplate::_add(const pl_char* str)
{
#if defined(PL_ANSI)
	int lenNew = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);

	_expand(sizeof(WORD)*lenNew);
	MultiByteToWideChar(CP_ACP, 0, str, -1, (LPWSTR)(_pMemory + _curSize), lenNew);

#elif defined(PL_UNICODE)
	pl_uint32 lenNew = pl_strlen(str)+1;
	_expand(sizeof(WORD)*lenNew);
	memcpy(_pMemory + _curSize, str, sizeof(pl_char)*lenNew);
#else
#error "Wrong String type"
#endif

	_curSize += sizeof(WORD)*lenNew;
	return;
	}

/**
	Align memory to the nearest align factor
*/
void DlgTemplate::_align(size_t align)
{
	BYTE zeroByte = 0;
	while (_curSize % align)
	{
		_add(&zeroByte, sizeof(BYTE));
	}
	return;
	}

/**
	Expand memory
*/
bool DlgTemplate::_expand(size_t size)
{
	if (_curSize + size < _memSize)
	{
		// Expand is not needed
		return true;
	}

	pl_uint8* pNewMem = (pl_uint8*)LocalAlloc(LPTR, _memSize + _MEM_BLOCK_SIZE);

	if (pNewMem == NULL)
	{
		return false;
	}
	memcpy(pNewMem, _pMemory, _curSize);
	_pNControls += (pNewMem-_pMemory);
	_memSize += _MEM_BLOCK_SIZE;
	LocalFree(_pMemory);
	_pMemory = pNewMem;
	return true;
}

} // namespace pl

//
// End of file 'pulsar_dlgtemplate_win.cpp'
//
